use crate::json_dumper::dump_json_node;
use std::collections::HashMap;
use std::fmt::{Display, Formatter};

#[derive(Debug, Clone, Default, PartialEq)]
pub enum JsonNode {
    Object(HashMap<String, JsonNode>),
    Array(Vec<JsonNode>),
    String(String),
    Number(f64),
    Boolean(bool),
    #[default]
    Null,
}

impl JsonNode {
    pub fn new() -> JsonNode {
        JsonNode::Null
    }

    pub fn dump(&mut self, indent: usize, escape_string: bool) -> String {
        dump_json_node(&self, indent, escape_string)
    }

    /// 往数组里面放数据
    pub fn push(&mut self, value: JsonNode) {
        match self {
            JsonNode::Array(arr) => arr.push(value),
            _ => panic!("Cannot push into non-array type"),
        }
    }

    /// 用于提前分配足够的内存，以容纳更多元素。
    pub fn reserve(&mut self, additional: usize) {
        match self {
            JsonNode::Array(arr) => arr.reserve(additional),
            _ => panic!("Cannot reserve into non-array type"),
        }
    }
    pub fn len(&mut self) -> usize {
        match self {
            JsonNode::Object(obj) => obj.len(),
            JsonNode::Array(arr) => arr.len(),
            _ => panic!("Cannot get length of non-object or non-array type"),
        }
    }

    pub fn resize(&mut self, new_len: usize) {
        match self {
            JsonNode::Array(arr) => {
                arr.resize(new_len, JsonNode::Null);
            }
            _ => panic!("Cannot resize non-array type"),
        }
    }

    pub fn clear(&mut self) {
        match self {
            JsonNode::Object(obj) => {
                obj.clear();
            }
            JsonNode::Array(arr) => {
                arr.clear();
            }
            _ => panic!("Cannot clear non-object or non-array type"),
        }
    }

    pub fn remove(&mut self, key: &str) -> Option<JsonNode> {
        match self {
            JsonNode::Object(obj) => obj.remove(key),
            _ => panic!("Cannot remove from non-object type"),
        }
    }

    pub fn contains_key(&self, key: &str) -> bool {
        match self {
            JsonNode::Object(obj) => obj.contains_key(key),
            _ => panic!("Cannot check key in non-object type"),
        }
    }

    pub fn set_null(&mut self) {
        *self = JsonNode::Null;
    }
}

/// 把 token 解析成 json 字符串 格式
/// {"friends": [{"name": "Tommy", "age": 20}, {"age": 20, "name": "Joe"}], "university": "UBC", "address": {"street": "1935 Lower Mall", "city": "Vancouver", "postal_code": "V6T 1X1"}, "is_student": true, "age": 20, "first name": "Yiran", "courses": [{"name": "CPEN 212", "credits": 4}, {"credits": 4, "name": "CPSC 221"}, {"credits": 3, "name": "Math 256"}], "graduated": false, "last name": "王"}
impl Display for JsonNode {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            JsonNode::Object(obj) => {
                write!(f, "{{")?;
                for (idx, (key, value)) in obj.iter().enumerate() {
                    write!(f, "\"{}\": ", key)?;
                    value.fmt(f)?;
                    if idx != obj.len() - 1 {
                        write!(f, ", ")?;
                    }
                }
                write!(f, "}}")?;
            }
            JsonNode::Array(arr) => {
                write!(f, "[")?;
                for (idx, value) in arr.iter().enumerate() {
                    value.fmt(f)?;
                    if idx != arr.len() - 1 {
                        write!(f, ", ")?;
                    }
                }
                write!(f, "]")?;
            }
            JsonNode::String(str) => {
                write!(f, "\"{}\"", str)?;
            }
            JsonNode::Number(num) => {
                write!(f, "{}", num)?;
            }
            JsonNode::Boolean(bool) => {
                write!(f, "{}", bool)?;
            }
            JsonNode::Null => {
                write!(f, "null")?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_reserve() {
        let mut json_node = JsonNode::Array(Vec::new());
        // 提前分配内存，以容纳 10 个元素
        json_node.reserve(10);
        // 验证容量是否足够
        if let JsonNode::Array(arr) = &json_node {
            println!("Current capacity: {}", arr.capacity()); // 应该至少为 10
        }
        for i in 0..10 {
            json_node.push(JsonNode::Number(i as f64));
        }
        if let JsonNode::Array(arr) = &json_node {
            println!("Array elements: {:?}", arr);
        }
    }
    #[test]
    fn test_len() {
        let mut json_node = JsonNode::Array(Vec::new());
        for i in 0..100 {
            json_node.push(JsonNode::Number(i as f64));
        }
        println!("len: {:?}", json_node.len());
    }


    #[test]
    fn test_clear_object() {
        let mut json = JsonNode::Object(vec![
            ("key1".to_string(), JsonNode::String("value1".to_string())),
            ("key2".to_string(), JsonNode::Number(42.0)),
        ].into_iter().collect());

        json.clear();
        assert!(matches!(json, JsonNode::Object(obj) if obj.is_empty()));
    }

    #[test]
    fn test_clear_array() {
        let mut json = JsonNode::Array(vec![
            JsonNode::String("item1".to_string()),
            JsonNode::Number(42.0),
        ]);

        json.clear();
        assert!(matches!(json, JsonNode::Array(arr) if arr.is_empty()));
    }

    #[test]
    #[should_panic(expected = "Cannot clear non-object or non-array type")]
    fn test_clear_invalid_type() {
        let mut json = JsonNode::String("not an object or array".to_string());
        json.clear();
    }



    #[test]
    fn test_remove_existing_key() {
        let mut json = JsonNode::Object(vec![
            ("key1".to_string(), JsonNode::String("value1".to_string())),
            ("key2".to_string(), JsonNode::Number(42.0)),
        ].into_iter().collect());

        let removed = json.remove("key1").unwrap();
        assert!(matches!(removed, JsonNode::String(s) if s == "value1"));
        assert!(!json.contains_key("key1"));
    }

    #[test]
    fn test_remove_nonexistent_key() {
        let mut json = JsonNode::Object(vec![
            ("key1".to_string(), JsonNode::String("value1".to_string())),
        ].into_iter().collect());

        assert!(json.remove("key2").is_none());
    }

    #[test]
    #[should_panic(expected = "Cannot remove from non-object type")]
    fn test_remove_invalid_type() {
        let mut json = JsonNode::Array(vec![JsonNode::String("item1".to_string())]);
        json.remove("key1");
    }

    #[test]
    fn test_contains_key() {
        let json = JsonNode::Object(vec![
            ("key1".to_string(), JsonNode::String("value1".to_string())),
            ("key2".to_string(), JsonNode::Number(42.0)),
        ].into_iter().collect());

        assert!(json.contains_key("key1"));
        assert!(json.contains_key("key2"));
        assert!(!json.contains_key("key3"));
    }

    #[test]
    #[should_panic(expected = "Cannot check key in non-object type")]
    fn test_contains_key_invalid_type() {
        let json = JsonNode::Array(vec![JsonNode::String("item1".to_string())]);
        json.contains_key("key1");
    }

    #[test]
    fn test_set_null() {
        let mut json = JsonNode::Object(vec![
            ("key1".to_string(), JsonNode::String("value1".to_string())),
        ].into_iter().collect());

        json.set_null();
        assert!(matches!(json, JsonNode::Null));
    }
}
